#pragma once

#include "LiteXMLPhaser.h"

class CXmlConfig
{
//Type and Structs
public:
	typedef struct _ConfigEntry {
		wstring wstrContent;
		vector<wstring> vecAttr;
		vector<wstring> vecAttrValue;

		_ConfigEntry() : wstrContent(L"") {}
		_ConfigEntry(LPCWSTR lpcwstrContent) : wstrContent(lpcwstrContent) {}

		LRESULT AddAttribute(LPCWSTR lpcwstrAttr, LPCWSTR lpcwstrValue)
		{
			//No Exist, add that attr
			if(CheckAttrExist(lpcwstrAttr) == vecAttr.end())
			{
				vecAttr.push_back(lpcwstrAttr);
				vecAttrValue.push_back(lpcwstrValue);
				return S_OK;
			}
			else
			{
				return S_FALSE;
			}
		}

		LRESULT RemoveAttribute(LPCWSTR lpcwstrAttr)
		{
			vector<wstring>::iterator it = CheckAttrExist(lpcwstrAttr);
			//Exist Attr, Remove that
			if(it != vecAttr.end())
			{
				vector<wstring>::iterator it1 = vecAttr.begin();
				vector<wstring>::iterator it2 = vecAttrValue.begin();

				while(it1 != it)
				{
					++it1;
					++it2;
				}

				vecAttr.erase(it1);
				vecAttrValue.erase(it2);

				return S_OK;
			}
			else
			{
				return S_FALSE;
			}
		}

		LRESULT SetAttribute(LPCWSTR lpcwstrAttr, LPCWSTR lpcwstrValue)
		{
			vector<wstring>::iterator it = CheckAttrExist(lpcwstrAttr);

			//Exist Attr, reset related attr value
			if(it != vecAttr.end())
			{
				vector<wstring>::iterator it1 = vecAttr.begin();
				vector<wstring>::iterator it2 = vecAttrValue.begin();

				while(it1 != it)
				{
					++it1;
					++it2;
				}

				*it2 = lpcwstrValue;

				return S_OK;
			}
			else
			{
				return S_FALSE;
			}
		}

		void SetContent(LPCWSTR lpcwstrContent)
		{
			wstrContent = lpcwstrContent;
		}

		vector<wstring>::iterator CheckAttrExist(LPCWSTR lpcwstrAttr)
		{
			for(vector<wstring>::iterator it = vecAttr.begin(); it != vecAttr.end(); ++it)
			{
				if(*it == lpcwstrAttr)
				{
					return it;
				}
			}

			return vecAttr.end();
		}

	} ConfigEntry;

	typedef struct _ConfigSection : CLiteXMLPhaser::XMLElements {

		_ConfigSection() {}
		_ConfigSection(LPCWSTR lpcwstrElementName, bool isCDATA = false) : _XMLElements(lpcwstrElementName, isCDATA) {}
		
		ConfigEntry* CreateConfigEntry(LPCWSTR lpcwstrContent)
		{
			ConfigEntry* pEntry = new ConfigEntry(lpcwstrContent);
			AddConfigEntry(pEntry);
			return pEntry;
		}

		ConfigEntry* CreateConfigEntry()
		{
			ConfigEntry* pEntry = new ConfigEntry;
			AddConfigEntry(pEntry);
			return pEntry;
		}

		void AddConfigEntry(ConfigEntry* pConfEntry)
		{
			AddElement(&(pConfEntry->wstrContent), &(pConfEntry->vecAttr), &(pConfEntry->vecAttrValue));
		}
		
	} ConfigSection;

	typedef struct _ConfigGroup : CLiteXMLPhaser::XMLPart {
		_ConfigGroup() {}
		_ConfigGroup(LPCWSTR lpcwstrPartName, bool isHaveSonNode, void* pNode, _XMLPart* pSiblingPointer = NULL) 
			: _XMLPart(lpcwstrPartName, isHaveSonNode, pNode, pSiblingPointer) {}
		
		_ConfigGroup* SetSonGroup(_ConfigGroup* pConfSonGrp)
		{
			//Set Must have a son node
			ATLASSERT(bIsSon && (pSonOrList == NULL));
			_ConfigGroup* pPreGrp = (_ConfigGroup*)pSonOrList;
			pSonOrList = pConfSonGrp;

			//Return pevious grp, this only happend in a release version
			return pPreGrp;
		}

		_ConfigGroup* SetSiblingGroup(_ConfigGroup* pConfSiblingGrp)
		{
			//Set Must have a son node
			ATLASSERT(pxmlPartSibling == NULL);
			_ConfigGroup* pPreGrp = (_ConfigGroup*)pxmlPartSibling;
			pxmlPartSibling = pConfSiblingGrp;

			//Return pevious grp
			return pPreGrp;
		}

	} ConfigGroup;

public:
	CXmlConfig() : m_pXmlRootFile(NULL), m_pXmlRootGroupNow(NULL), m_wstrXmlFileName(L""), m_wstrXmlRootName(L"") {}
	CXmlConfig(LPCWSTR lpcwstrXMLSettingFileName) 
		: m_pXmlRootFile(NULL), m_pXmlRootGroupNow(NULL), m_wstrXmlFileName(lpcwstrXMLSettingFileName), m_wstrXmlRootName(L"") {}
	~CXmlConfig();

public:
	HRESULT getNextCDATA(LPCWSTR lpcwstrFileRelName, LPCWSTR lpwszElementPath, LPCWSTR lpwszPropPath, LPWSTR lpwszCDATA, bool bSubCall = false);		/* Make Sure the path is like /root/level1/level2, PropPath with /prop/value, do not surport <tag/> closed like this */
	HRESULT getNextText(LPCWSTR lpcwstrFileRelName, LPCWSTR lpwszElementPath, LPCWSTR lpwszPropPath, LPWSTR lpwszText, bool bSubCall = false);			/* Make Sure the path is like /root/level1/level2, PropPath with /prop/value, do not surport <tag/> closed like this */

	void SetRootNodeName(LPCWSTR lpcwstrRootNodeName);																								//Set the root node name and create it
	void FlushConfigsToDisk();																														//Flush to all setttings to disk
	ConfigGroup* AddToRootGroup(ConfigGroup* pconfGrp);																								//Add a config group to root

	ConfigGroup* CreateConfigGroup(LPCWSTR lpcwstrGroupName);																						//Create Empty group has son node
	ConfigSection* CreateConfigSection(LPCWSTR lpwcstrSectionName, LPCWSTR lpwcstrEntryName, bool isCDATA, ConfigGroup** ppConfigGroup);			//Create Group with node

private:
	CLiteXMLPhaser::XMLFile* m_pXmlRootFile;			//Root XML file pointer
	ConfigGroup* m_pXmlRootGroupNow;					//Now Root XML part pointer
	wstring m_wstrXmlFileName;							//Config XML Filename
	wstring m_wstrXmlRootName;							//XML Root Name
};
